﻿/** \file
* \par Subversion URL:
* \$URL: http://planar-rendering.googlecode.com/svn/trunk/frontend/src/RangeTable.cs $
* \version \$Rev: 74 $
* \date    \$Date: 2009-04-20 01:12:01 +0000 (Mon, 20 Apr 2009) $
*/

using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace Frontend
{
	/// <summary>
	/// A table of ranges, where each row represents a range whose properties can
	/// be modified by the user.
	/// </summary>
	class RangeTable : TableLayoutPanel
	{
		/// <summary>The current number of spatial checks set to true.</summary>
		int nspatials;

		/// <summary>The list of spatial checks.</summary>
		List<CheckBox> spatials = new List<CheckBox>();

		/// <summary>
		/// The constructor. Sets the heading labels.
		/// </summary>
		public RangeTable()
		{
			List<string> headings = new List<string>
			{
				"Function\nnumber",
				"Property\nname",
				"Low",
				"High",
				"Resolution",
				"Spatial\n(Max 3)"
			};
			for (int i = 0; i < headings.Count; i++ )
			{
				Label heading = new Label();
				heading.AutoSize = true;
				heading.Text = headings[i];
				Controls.Add(heading, i, 0);
			}
		}

		/// <summary>
		/// Add a range to the table.
		/// </summary>
		/// <param name="range">The range to add.</param>
		/// <param name="funcindex">The function index to display.</param>
		public void AddRange(Range range, int funcindex)
		{
			Label function = new Label();
			Label name = new Label();
			NumericUpDown low = new NumericUpDown();
			NumericUpDown high = new NumericUpDown();
			NumericUpDown res = new NumericUpDown();
			CheckBox spatial = new CheckBox();

			function.Text = (funcindex > 0) ?
				funcindex.ToString() : "(all)";
			function.AutoSize = true;

			name.Text = range.name;
			name.AutoSize = true;

			low.ValueChanged += new EventHandler(delegate(object sender, EventArgs e)
				{
					Range thisrange = GetRange(sender);
					decimal val = low.Value;
					if (high.Enabled)
					{
						thisrange.low = (double)val;
						high.Minimum = val;
					}
					else
						thisrange.presval = (double)val;
				});
			high.ValueChanged += new EventHandler(delegate(object sender, EventArgs e)
				{
					decimal val = high.Value;
					GetRange(sender).high = (double)val;
					low.Maximum = val;
				});
			res.ValueChanged += new EventHandler(delegate(object sender, EventArgs e)
				{
					high.Enabled = res.Value > 1;
					Range thisrange = GetRange(sender);
					if (res.Value == 1)
					{
						low.Maximum = 100;
						low.Value = (decimal)thisrange.presval;
					}
					else if (thisrange.res == 1)
					{
						low.Value = (decimal)thisrange.low;
						high.Value = (decimal)thisrange.high;
					}
						
					thisrange.res = (int)res.Value;
				});
			spatial.CheckedChanged += new EventHandler(delegate(object sender, EventArgs e)
			{
				GetRange(sender).spatial = spatial.Checked;
				if (spatial.Checked)
				{
					if (res.Value == 1)
						res.Value = 200;
					nspatials++;
					if (nspatials == 3)
						foreach (CheckBox check in spatials)
							if (!check.Checked)
								check.Enabled = false;
				}
				else
				{
					res.Value = 1;
					if (nspatials == 3)
						foreach (CheckBox check in spatials)
							check.Enabled = true;
					nspatials--;
				}
			});

			low.Tag = range;
			low.DecimalPlaces = 6;
			low.Minimum = -100;
			low.Increment = 0.1M;

			high.Tag = range;
			high.DecimalPlaces = 6;
			high.Maximum = 100;
			high.Increment = 0.1M;
			high.Value = (decimal)range.high;

			res.Tag = range;
			res.Minimum = 1;
			res.Maximum = 1000;
			res.Increment = 10;
			res.Value = range.res;

			spatial.Tag = range;
			spatial.Checked = range.spatial;
			spatial.Enabled = range.spatial;
			spatials.Add(spatial);

			Controls.Add(function);
			Controls.Add(name);
			Controls.Add(low);
			Controls.Add(high);
			Controls.Add(res);
			Controls.Add(spatial);
		}

		/// <summary>
		/// Remove a range from this table.
		/// </summary>
		/// <param name="range">The range to remove.</param>
		public void RemoveRange(Range range)
		{
			foreach (CheckBox spatial in spatials)
			{
				if (spatial.Tag == range)
				{
					spatial.Checked = false;
					int index = Controls.GetChildIndex(spatial) - ColumnCount + 1;
					for (int c = 0; c < ColumnCount; c++)
						Controls.RemoveAt(index);
					spatials.Remove(spatial);
					return;
				}
			}
		}

		/// <summary>
		/// Get a reference to a range object from the tag of a control.
		/// </summary>
		/// <param name="control">The control, as an abstract object type.</param>
		/// <returns>The range object reference.</returns>
		Range GetRange(object control)
		{
			return (Range)((Control)control).Tag;
		}
	}
}
